1 Introduction

The Quality and Outcomes Framework (QOF) is a voluntary annual reward and incentive programme for all GP practices in England (NHSD, 2021a). The objective of the Quality and Outcomes Framework (QOF) is to improve the quality of care patients are given by rewarding practices for the quality of care they provide to their patients, based on a number of indicators across a range of key areas of clinical care and public health. QOF participation by GP practices is very high, with 96.7% of practices participating in the 2020/21 publication (NHSD, 2021b).

OpenSAFELY is a secure analytics platform for electronic patient records built by our group on behalf of NHS England to deliver urgent academic and operational research during the pandemic (e.g., Curtis et al., 2021; Williamson et al., 2020). Analyses can currently run across all patients’ full pseudonymised primary care records, with patient-level linkage to various sources of secondary care data. The OpenSAFELY-TPP is a Trusted Research Environment (TRE) containing the routine clinical data of 23.4m people, approximately 40% of England’s population.

Currently QOF reports are published at the end of the financial year, and consist of prevalence rates and indicator achievement rates for clinical areas by NHS geographic breakdowns from region to practice. We set out to replicate the indicator logic for a variety of QOF clinical indicators in OpenSAFELY-TPP and describe trends monthly over time, before and during the pandemic. We also describe how the indicators vary between key clinical, regional and demographic subgroups.

High blood pressure is one of the leading risk factors for several diseases (e.g., cardiovascular disease, stroke) worldwide. Research suggests that delays in the management of high blood pressure are associated with worse clinical outcomes, for example acute cardiovascular events, or death (Xu et al., 2015). This report describes the prevalence of people who have a diagnosis of hypertension which has not been subsequently resolved the OpenSAFELY-TPP trusted research environment (TRE).

2 Methods

Using OpenSAFELY-TPP, covering 40% of England’s population, we have evaluated the QOF Hypertension indicators (HYP001, HYP003, HYP007) between 2019-09-01 and 2022-03-31. The codelist used can be found here at OpenSAFELY Codelists.

The study population for the register was defined following the business rules the (v46). For each month within the study period, we have calculated the percentage of registered patients with a diagnosis of hypertension which has not been subsequently resolved. All analytical code and output is available for inspection at the OpenSAFELY GitHub repository.

2.1 Business rules

More details about the rules can be found here. Dashboards presenting the annual targets of all QOF indicators published by NHSD are available here.

2.1.1 HYP001 (Register)

The description and rules for the Hypertension Register (HYP001, Version: 46.0) are outlined below:

“Select patients from the specified population who have a diagnosis of hypertension which has not been subsequently resolved.”

Rule number Rule Action if true Action if false Rule description or comments
1 If HYPLAT_DAT ≠ Null AND If HYPRES_DAT = Null Select Reject Select patients from the specified population who have a diagnosis of hypertension which has not been subsequently resolved. Reject the remaining patients.

2.2 Codelists

2.2.1 Hypertension Refsets

Cluster name Description SNOMED CT
BP_COD Blood pressure (BP) recording codes ^999012731000230108
BPDEC_COD Codes indicating the patient has chosen not to have blood pressure procedure ^999012611000230106
HTMAX_COD Codes for maximal blood pressure (BP) therapy ^999006651000230109
HYP_COD Hypertension diagnosis codes ^999006611000230105
HYPINVITE_COD Invite for hypertension care review codes ^999012971000230108
HYPPCADEC_COD Codes indicating the patient has chosen not to receive hypertension quality indicator care ^999013091000230102
HYPPCAPU_COD Codes for hypertension quality indicator care unsuitable for patient ^999013211000230104
HYPRES_COD Hypertension resolved codes ^999006531000230101

2.2.2 Breakdowns

Codelist name Description Coding system
Ethnicity A list of ethnicity codes in use in UK general practice including aggregate grouping at two levels (6 and 16). CTV3
NHS England Care Homes residential status This codelists supports analysis of records of people who may reside in a nursing or care home. SNOMED CT
Learning disability (LD) codes The following codes are used to check for a record of learning disability. SNOMED CT

3 Results

Note that the scaling of the y-axis is different for the total population (0 to 100%) and outputs by subgroup (scaling differs across grouping variables to highlight differences between groups). SMALL NUMBER REDACTION.

3.1 HYP001 (Register)

3.1.1 Total population

df_measures_hyp001 %>%
  dplyr::filter(group == "population") %>%
  plot_qof_indicator(
    value = value,
    y_scale = "percent",
    geom_segment = TRUE,
    legend = "none",
    y_label = "Prevalence (%)",
    set_y_scale_limits = TRUE)

df_measures_hyp001 %>%
  dplyr::filter(group == "population") %>%
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    legend = "none",
    x_scale_date_breaks = "4 months",
    geom_segment = TRUE,
    y_label = "Prevalence (Count)",
    set_y_scale_limits = TRUE)

3.1.2 Sex

df_measures_hyp001 %>%
  dplyr::filter(group == "sex") %>%
  dplyr::mutate(category = factor(category,
    levels = c("F", "M"),
    labels = c("Female", "Male")
  )) %>%
  plot_qof_indicator(
    value = value,
    y_scale = "percent",
    y_label = "Prevalence (%)") +
  scale_colour_brewer(palette = "Dark2")

df_measures_hyp001 %>%
  dplyr::filter(group == "sex") %>%
  dplyr::mutate(category = factor(category,
                                  levels = c("F", "M"),
                                  labels = c("Female", "Male"))) %>%
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)") +
  scale_colour_brewer(palette = "Dark2")

3.1.3 Age band

df_measures_hyp001 %>%
  dplyr::filter(group == "age_band") %>%
  dplyr::filter(category != "missing") %>%
  plot_qof_indicator(
    value = value,
    y_scale = "percent",
    y_label = "Prevalence (%)")

df_measures_hyp001 %>%
  dplyr::filter(group == "age_band") %>%
  dplyr::filter(category != "missing") %>%
    plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)")

3.1.4 IMD

df_measures_hyp001 %>%
  dplyr::filter(group == "imd") %>%
  dplyr::mutate(category = factor(category,
    levels = c(1:5),
    labels = c("1 - Most deprived", "2", "3", "4", "5 - Least deprived")
  )) %>%
  plot_qof_indicator(
    value = value,
    y_scale = "percent",
    y_label = "Prevalence (%)")

df_measures_hyp001 %>%
  dplyr::filter(group == "imd") %>%
  dplyr::mutate(category = factor(category,
    levels = c(1:5),
    labels = c("1 - Most deprived", "2", "3", "4", "5 - Least deprived")
  )) %>% 
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)")

3.1.5 Ethnicity

df_measures_hyp001 %>%
  dplyr::filter(group == "ethnicity") %>%
    plot_qof_indicator(
    value = value,
    y_scale = "percent",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (%)") +
  scale_colour_brewer(palette = "Dark2")

df_measures_hyp001 %>%
  dplyr::filter(group == "ethnicity") %>%
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)") +
  scale_colour_brewer(palette = "Dark2")

3.1.6 Region

df_measures_hyp001 %>%
  dplyr::filter(group == "region") %>%
    plot_qof_indicator(
    value = value,
    y_scale = "percent",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (%)") +
  scale_colour_brewer(palette = "Set1")

df_measures_hyp001 %>%
  dplyr::filter(group == "region") %>%
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)") +
  scale_colour_brewer(palette = "Set1")

3.1.7 Learning disability

df_measures_hyp001 %>%
  dplyr::filter(group == "learning_disability") %>%
  dplyr::mutate(category = factor(category,
    levels = c(TRUE, FALSE),
    labels = c(
      "Record of learning disability",
      "No record of learning disability"
    )
  )) %>%
      plot_qof_indicator(
    value = value,
    y_scale = "percent",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (%)") +
  scale_colour_brewer(palette = "Dark2")

df_measures_hyp001 %>%
  dplyr::filter(group == "learning_disability") %>%
  dplyr::mutate(category = factor(category,
    levels = c(TRUE, FALSE),
    labels = c(
      "Record of learning disability",
      "No record of learning disability"
    )
  )) %>%
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)") +
  scale_colour_brewer(palette = "Dark2")

3.1.8 Care home status

df_measures_hyp001 %>%
  dplyr::filter(group == "care_home") %>%
  dplyr::mutate(category = factor(category,
    levels = c(TRUE, FALSE),
    labels = c(
      "Record of positive care home status",
      "No record of positive care home status"
    )
  )) %>%
      plot_qof_indicator(
    value = value,
    y_scale = "percent",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (%)") +
  scale_colour_brewer(palette = "Dark2")

df_measures_hyp001 %>%
  dplyr::filter(group == "care_home") %>%
  dplyr::mutate(category = factor(category,
    levels = c(TRUE, FALSE),
    labels = c(
      "Record of positive care home status",
      "No record of positive care home status"
    )
  )) %>%
  plot_qof_indicator(
    value = hypertension,
    y_scale = "count",
    x_scale_date_breaks = "4 months",
    y_label = "Prevalence (Count)") +
  scale_colour_brewer(palette = "Dark2")

4 Discussion

  • TODO

5 References

  1. Curtis HJ, MacKenna B, Croker R, Inglesby P, Walker AJ, Morley J, et al. OpenSAFELY NHS Service Restoration Observatory 1: describing trends and variation in primary care clinical activity for 23.3 million patients in England during the first wave of COVID-19. Br J Gen Pract [Internet]. 2021 Sep 20 [cited 2021 Oct 5]; Available from: https://bjgp.org/content/early/2021/09/24/BJGP.2021.0380
  2. Williamson EJ, Walker AJ, Bhaskaran K, Bacon S, Bates C, Morton CE, et al. Factors associated with COVID-19-related death using OpenSAFELY. Nature. 2020 Aug;584(7821):430–6. https://www.nature.com/articles/s41586-020-2521-4
  3. Xu W, Goldberg SI, Shubina M, Turchin A. Optimal systolic blood pressure target, time to intensification, and time to follow-up in treatment of hypertension: population based retrospective cohort study. BMJ. 2015 Feb 5;350:h158. https://www.bmj.com/content/350/bmj.h158